package com.vecspace.httpclient;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.vecspace.utils.TJSON;
import com.vecspace.utils.log.HLogger;

/**同一个实例，会保持session
 * 发送http请求，并获得正常返回的内容，非正常返回内容的情况下抛出异常
 * 采用UTF-8的默认编码
 * @author: wanghua
 */
public class TSessionHttpClient {

	/** 一：连接超时：connectionTimeout 指的是连接一个url的连接等待时间。测试的时候，将url改为一个不存在的url：“http://test.com”超时时间3000ms过后，系统报出异常。
	 *  二：读取数据超时：soTimeout 指的是连接上一个url，获取response的返回等待时间
	 */
	private int connectionRequestTimeout = 10 * 1000; //从连接池获取连接的timeout
	private int connectTimeout = 30 * 1000;//和服务器建立连接的timeout
	private int socketTimeout = 3 * 60 * 1000; //从服务器读取数据的timeout
	
	public String get(String httpUrl) throws Exception{
		return get(httpUrl, charset);
	}
	
	public String get(String url , String charset) throws HttpException{
		HLogger.DEFAULT().info(url);
		HttpGet httpRequest = new HttpGet(url);

		RequestConfig requestConfig = RequestConfig.custom()
	    	.setConnectionRequestTimeout(connectionRequestTimeout)//milliseconds 
	    	.setConnectTimeout(connectTimeout)  //milliseconds 
	    	.setSocketTimeout(socketTimeout).build();
		
		httpRequest.setConfig(requestConfig);
		HttpResponse httpResponse = null;
		try {
			httpResponse = httpClient.execute(httpRequest);
		} catch (IOException e1) {			
			throw new HttpException(-1, e1.getMessage(), url, "");
		}
		int statusCode = httpResponse.getStatusLine().getStatusCode();
		
		if (statusCode == HttpStatus.SC_OK) {
			String result = "";
			try{
				result = EntityUtils.toString(httpResponse.getEntity(), charset);
			}catch(Exception e){
				throw new HttpException(statusCode, e.getMessage(), url, "");
			}
			return result; 
		} else {
			String result = "";
			try{
				result = EntityUtils.toString(httpResponse.getEntity(), charset);
			}catch(Exception e){
				result = e.getMessage();
			}
			throw new HttpException(statusCode, result, url, "");
		}
	}

	public String post(String url) throws Exception{
		return post(url, null, charset);
	}
	
	public String post(String url,Map<String,Object> parameters) throws Exception{
		return post(url, parameters, charset);
	}
	
	public String post(String url,Map<String,Object> parameters, String charset) throws Exception{
		HLogger.DEFAULT().info(url);
		String baseUrl = url;
		int splitIdx = url.indexOf("?");
		if(splitIdx > 0){
			String[] arr = url.split("\\?",2);
			if(arr.length > 1){
				String queryString = arr[1];
				baseUrl = arr[0];
				String[] params = queryString.split("&");
				for(String paramStr : params){
					String[] kv = paramStr.split("=",2);
					String key="",value = "";
					if(kv.length > 1){
						key = kv[0];
						value = kv[1];
					}else if(kv.length == 1){
						key = kv[0];
					}
					if(parameters == null) {
						parameters = new HashMap<String,Object>();
					}
					parameters.put(key, value);
				}
			}
		}
		HttpPost httpRequest = new HttpPost(baseUrl);
		List<NameValuePair> params = new ArrayList<NameValuePair>(); 
		if(parameters != null && parameters.size()>0){
			for(String key : parameters.keySet()){
				Object val = parameters.get(key);
				if(val != null){
					String strVal = "";
					if(val instanceof String 
							|| val instanceof Integer || val instanceof Character
							|| val instanceof Double || val instanceof Float
							|| val instanceof Short || val instanceof Long
							|| val instanceof Byte || val instanceof Boolean){
						strVal = val.toString();
					}else{
						strVal = TJSON.toJSONString(val);
					}
					params.add(new BasicNameValuePair(key,strVal));
				}else{
					 params.add(new BasicNameValuePair(key,""));					 
				}
			}
		}
		
		RequestConfig requestConfig = RequestConfig.custom()
    	.setConnectionRequestTimeout(connectionRequestTimeout)//milliseconds 
    	.setConnectTimeout(connectTimeout)  //milliseconds 
    	.setSocketTimeout(socketTimeout).build();
		int statusCode = -1;
		httpRequest.setConfig(requestConfig);
		try{
			HttpEntity httpEntity = new UrlEncodedFormEntity(params, charset);
	
			httpRequest.setEntity(httpEntity);
	
			HttpResponse httpResponse = httpClient.execute(httpRequest);
			statusCode = httpResponse.getStatusLine().getStatusCode();
			
			if (statusCode == HttpStatus.SC_OK) {
				String result = EntityUtils.toString(httpResponse.getEntity(), charset);
				return result; 
			} else {
				String result = EntityUtils.toString(httpResponse.getEntity(), charset);
				throw new HttpException(statusCode, result, url, TJSON.toJSONString(parameters));
			}
		}catch(HttpException e){
			throw e;
		}catch(Exception e){
			throw new HttpException(statusCode, e.getMessage(), url, TJSON.toJSONString(parameters));
		}
	}
	/**
	 * 
	 * @param wsurl webservice地址
	 * @param soapRequestData 请求数据（soap文本）
	 * @param mimeType 默认为 text/xml
	 * @param charset 字符集
	 * @return
	 * @throws Exception
	 * @author: wanghua
	 */
	public String postWSSoap(String wsurl, String soapRequestData, String mimeType, String charset) throws Exception{
		HttpPost httpRequest = new HttpPost(wsurl);//"http://epacketws.pushauction.net/v3/orderservice.asmx?wsdl"
		// 然后把Soap请求数据添加到PostMethod中
		if(charset == null || charset.length() == 0) {
			charset = "utf-8";
		}
		byte[] b = soapRequestData.getBytes(charset);
		try(InputStream is = new ByteArrayInputStream(b, 0, b.length)){
			if(mimeType == null || mimeType.trim().length() == 0) {
				mimeType = "text/xml";
			}
			ContentType contentType =  ContentType.create(mimeType, charset);
			HttpEntity entity = new InputStreamEntity(is, b.length, contentType);//(is, b.length, "application/soap+xml; charset="+getCharset());
			httpRequest.setEntity(entity);
		}
		
		HttpResponse httpResponse = httpClient.execute(httpRequest);
		int statusCode = httpResponse.getStatusLine().getStatusCode();

		if (statusCode == HttpStatus.SC_OK) {
			String soapResponseData = EntityUtils.toString(httpResponse.getEntity(), charset);
			return soapResponseData; 
		} else {
			String result = EntityUtils.toString(httpResponse.getEntity(), charset);
			throw new Exception(statusCode+":"+ wsurl +"\r\n"+result);
		}		 
	}
	
	private CloseableHttpClient httpClient;
	private String charset = "UTF-8";
	public TSessionHttpClient(){ 
		//HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
		//httpClientBuilder.build();
		httpClient = HttpClients.createDefault();
	}
	
	public void close(){
		if(httpClient != null){
			try {
				httpClient.close();
			} catch (IOException e) {				
				e.printStackTrace();
			}
		}
	}
	
	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	/**读取数据超时,指的是连接上一个url，获取response的返回等待时间 毫秒*/
	public int getSocketTimeout() {
		return socketTimeout;
	}

	/**读取数据超时,指的是连接上一个url，获取response的返回等待时间 毫秒*/
	public void setSocketTimeout(int socketTimeout) {
		this.socketTimeout = socketTimeout;
	}

	public int getConnectionRequestTimeout() {
		return connectionRequestTimeout;
	}

	/**
	 * 连接超时：connectionTimeout 指的是连接一个url的连接等待时间。测试的时候，将url改为一个不存在的url：“http://test.com”超时时间3000ms过后，系统报出异常。
	 * @param connectionRequestTimeout
	 */
	public void setConnectionRequestTimeout(int connectionRequestTimeout) {
		this.connectionRequestTimeout = connectionRequestTimeout;
	}

	public int getConnectTimeout() {
		return connectTimeout;
	}

	public void setConnectTimeout(int connectTimeout) {
		this.connectTimeout = connectTimeout;
	}
}
